using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Framework.Serialization;
using IQIGame.Onigao.Game;
using System.Collections.Generic;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    /// <summary>
    /// 剧情控制器
    /// </summary>
    public class StoryDialogModule : Singleton<StoryDialogModule>
    {
        #region Variable & Const

        private UIStorySystem uiStorySystem;

        public bool isPlaying { get; private set; }

        private Queue<(int, int)> _waitingStoryIds = new Queue<(int, int)>();

        /// <summary>
        /// 排队时等待的任务，所有对话完成后结束
        /// </summary>
        private Queue<AutoResetUniTaskCompletionSource> _waitingTasks = new Queue<AutoResetUniTaskCompletionSource>();

        #endregion

        #region Init & Dispose
        public void Init()
        {

        }

        public void Dispose()
        {
            uiStorySystem?.Close();
        }


        #endregion

        private StoryDialogModule()
        {

        }

        public UniTask StartPlayStoryById(int storyId)
        {
            return StartPlayStoryById(storyId, 0);
        }

        public UniTask StartPlayStoryById(int storyId, int jumpCid)
        {
            if (!isPlaying)
            {
                return StartPlayStory(storyId, jumpCid);
            }
            _waitingStoryIds.Enqueue((storyId, jumpCid));
            var waitingTask = AutoResetUniTaskCompletionSource.Create();
            _waitingTasks.Enqueue(waitingTask);
            return waitingTask.Task;
        }

        private async UniTask StartPlayStory(int storyId, int jumpCid)
        {
            var storyCfg = TableCenter.storyDialog.Get(storyId);
            if (storyCfg == null)
            {
                return;
            }
            await this.StartPlayStory(storyCfg.Name, jumpCid);
            CheckNextWaitingStory().Forget(); //此处不必等待，让上一个对话正确结束，待NextWaitingStory结束时，会设置waitingTask为Complete，此时接下来的任务才算正式结束
        }


        private async UniTask StartPlayStory(string storyName, int jumpCid)
        {
            isPlaying = true;
            var taskui = ManagerCenter.UI.ShowWindowAsync<UIStorySystem>();

            // 加载配置
            ResLoader resloader = ResLoader.Create();
            var taskTextAsset = resloader.LoadABAssetAwait<TextAsset>(PathConstant.GetStoryCfgPath(storyName.ToLower()));


            // 小技巧之一：上面先调加载，后面一起等待，而不是一个一个await，这样可以同时加载多个
            await taskui;
            uiStorySystem = ManagerCenter.UI.GetEntityUI<UIStorySystem>();
            var textAsset = await taskTextAsset;
            var tbCfgStory = new CfgStory.TbCfgStoryShow(new ByteBuf(textAsset.bytes));
            resloader.Put2Pool();

            // 创建播放上下文数据
            var playContext = new StoryPlayContext(tbCfgStory, jumpCid);
            playContext.InitMessageSend(RepoStoryDialogSelection);

            // 开发播放
            await this.StartPlayStoryOne(playContext);

            isPlaying = false;
            if (_waitingStoryIds.Count == 0)
            {
                this.Dispose();
            }
        }

        public async UniTask CheckNextWaitingStory()
        {
            if (_waitingStoryIds.Count > 0) //播放等待中的对话（对话未完成时开启的对话会进入等待状态，等待的任务转为_waitingTasks）
            {
                //该方法不能直接由StartPlayStory结尾调用，因为要让上一个对话的任务正确结束
                //该方法应该由StartPlayStory最上层调用者处理完所有逻辑后调用
                //当前这条对话的任务其实是以_waitingTasks内的任务为准的(见StartPlayStoryById(int storyId))
                (int storyCid, int jumpCid) = _waitingStoryIds.Dequeue();
                await StartPlayStory(storyCid, jumpCid);
                _waitingTasks.Dequeue().TrySetResult();
            }
        }

        public async UniTask StartPlayStoryOne(StoryPlayContext playContext)
        {
            await uiStorySystem.PlayStoryAct(playContext);
        }

        private UniTask RepoStoryDialogSelection(List<int> idListForOptions, List<int> selectionIndexes)
        {
            return CLevelLogicModule.NetCore.CS_RepoStoryDialogSelection(selectionIndexes);
        }

    }
}
